#ifndef NJF_RASTER_TRIANGLES_H
#define NJF_RASTER_TRIANGLES_H

#include "raster-util.h"

/* edge functions */
/* w and dw are necessary for perspective correct rendering */
typedef struct
{
    MSC_ALIGNED(16) union
    {
        Fixed valvec[4];
        struct
        {
            Fixed u, v, x, w;
        };
    } GCC_ALIGNED(16);
    MSC_ALIGNED(16) union
    {
        Fixed delvec[4];
        struct
        {
            Fixed du, dv, dx, dw;
        };
    } GCC_ALIGNED(16);
    int y;
    int h;
} Edge;
typedef struct
{
    Fixed x, y, z;
    Fixed w, u, v;
} RasterVert;
typedef struct
{
    MSC_ALIGNED(16) union
    {
        Fixed vec0[4];
        struct
        {
            Fixed u0, v0, x0, w0;
        };
    } GCC_ALIGNED(16);
    MSC_ALIGNED(16) union
    {
        Fixed vec1[4];
        struct
        {
            Fixed u1, v1, x1, w1;
        };
    } GCC_ALIGNED(16);
} RasterSpan;

BEST_INLINE RasterVert VertFromPos(int x, int y)
{
    RasterVert ret;
    ret.x = IntToFixed(x);
    ret.y = IntToFixed(y);
    ret.z = ret.w = FIXED_ONE;
    ret.u = ret.v = 0;
    return ret;
}

BEST_INLINE RasterVert VertFromPosTex(int x, int y, int u, int v)
{
    RasterVert ret;
    ret.x = IntToFixed(x);
    ret.y = IntToFixed(y);
    ret.z = ret.w = FIXED_ONE;
    ret.u = IntToFixed(u);
    ret.v = IntToFixed(v);
    return ret;
}

EXTERNC void __cdecl PrepareEdge(Edge *edge, const RasterVert *pt1, const RasterVert *pt2);

BEST_INLINE int EdgeSkip(Edge *edge, int i)
{
    i = IMIN(edge->h, i);
    edge->x += edge->dx * i;
    edge->u += edge->du * i;
    edge->v += edge->dv * i;
    edge->w += edge->dw * i;
    edge->y += i;
    edge->h -= i;
    return edge->h;
}

BEST_INLINE int EdgeCrawl(Edge *edge)
{
    int h = edge->h;
    edge->x += edge->dx;
    edge->u += edge->du;
    edge->v += edge->dv;
    edge->w += edge->dw;
    edge->y++;
    edge->h--;
    return h;
}

/* span functions */

/* precondition: *x0 < *x1 */
BEST_INLINE int ClipSpan(const RasterRect *clip, int *x0, int *x1)
{
    if(*x1 < clip->x || *x0 > (clip->x + clip->w))
    {
        *x0 = 0; *x1 = 0;
        return 0;
    }
    if(*x1 > (clip->x + clip->w))
        *x1 = clip->x + clip->w;
    if(*x0 < clip->x)
        *x0 = clip->x;
    return 1;
}

EXTERNC int __cdecl ClipSpan2(const RasterRect *clip, RasterSpan *span);

/* precondition: *x0 < *x1 */
EXTERNC int __cdecl ClipSpanUV(const RasterRect *clip, int *x0, int *x1, RasterPosUV *uv0, RasterPosUV *uv1);

typedef int (__cdecl *SpanFn)(Raster *, Edge *, Edge *, void *args);

EXTERNC void (__cdecl * SpansBetween)(Raster *raster, Edge *edge0, Edge *edge1, SpanFn fn, void *args);

#endif /* NJF_RASTER_TRIANGLES_H */
